package edu.udo.sopra10.chaturaji.entities.transfer;

import static edu.udo.sopra10.chaturaji.entities.transfer.DiceRoll.EquivalenceClass.FOUR_OR_SIX;
import static edu.udo.sopra10.chaturaji.entities.transfer.DiceRoll.EquivalenceClass.ONE_OR_FIVE;
import static edu.udo.sopra10.chaturaji.entities.transfer.DiceRoll.EquivalenceClass.THREE;
import static edu.udo.sopra10.chaturaji.entities.transfer.DiceRoll.EquivalenceClass.TWO;
import edu.udo.sopra10.chaturaji.entities.pieces.Boat;
import edu.udo.sopra10.chaturaji.entities.pieces.Elephant;
import edu.udo.sopra10.chaturaji.entities.pieces.Horse;
import edu.udo.sopra10.chaturaji.entities.pieces.King;
import edu.udo.sopra10.chaturaji.entities.pieces.Pawn;

/**
 * The result of a dice roll. Includes the numerical result as well as the
 * consequence equivalence class.
 * 
 * @author Simon Dierl
 */
public final class DiceRoll {
	/**
	 * The consequence equivalence classes. These values are equivalent with
	 * respect to their in-game consequences.
	 * 
	 * @author Simon Dierl
	 */
	public enum EquivalenceClass {
		/**
		 * A four or a six, allows the {@link Elephant} to move.
		 */
		FOUR_OR_SIX,
		/**
		 * A one or a five, allows {@link Pawn} or {@link King} to move.
		 */
		ONE_OR_FIVE,
		/**
		 * A three, allows the {@link Horse} to move.
		 */
		THREE,
		/**
		 * A two, allows the {@link Boat} to move.
		 */
		TWO;
	}

	/**
	 * Get a roll's equivalence class.
	 * 
	 * @param roll
	 *            the roll result, must be in {@code [1, 6]}.
	 * @return the respective equivalence class.
	 */
	public static EquivalenceClass equivalenceClassFromRoll(final byte roll) {
		switch (roll) {
		case 1:
		case 5:
			return ONE_OR_FIVE;
		case 2:
			return TWO;
		case 3:
			return THREE;
		case 4:
		case 6:
			return FOUR_OR_SIX;
		default:
			throw new IllegalArgumentException("roll must be in [1, 6]");
		}
	}
	
	/**
	 * Get a piece's equivalence class.
	 * 
	 * @param piece
	 *            the piece.
	 * @return the respective equivalence class.
	 */
	public static EquivalenceClass equivalenceClassFromPiece(final edu.udo.sopra10.chaturaji.entities.pieces.Piece piece) {
		if ((piece instanceof Pawn) || (piece instanceof King)) {
			return ONE_OR_FIVE;
		} else if (piece instanceof Boat) {
			return TWO;
		} else if (piece instanceof Horse) {
			return THREE;
		} else {
			return FOUR_OR_SIX;
		}
	}

	/**
	 * The equivalence class the roll is in.
	 */
	private final EquivalenceClass equivalenceClass;

	/**
	 * The numerical result of the roll.
	 */
	private final byte roll;

	/**
	 * Create a new roll from a numerical roll result.
	 * 
	 * @param roll
	 *            the roll, must be in {@code [1, 6]}.
	 */
	public DiceRoll(final byte roll) {
		equivalenceClass = equivalenceClassFromRoll(roll);
		this.roll = roll;
	}

	@Override
	public boolean equals(final Object obj) {
		if (obj == this) {
			return true;
		} else if ((obj == null) || !(obj instanceof DiceRoll)) {
			return false;
		} else {
			return roll == ((DiceRoll) obj).roll;
		}
	}

	/**
	 * Get the equivalence class the roll is in.
	 * 
	 * @return the roll's equivalence class, never {@code null}.
	 */
	public EquivalenceClass getEquivalenceClass() {
		return equivalenceClass;
	}

	/**
	 * Get the numerical result of the roll.
	 * 
	 * @return the roll, always in {@code [1, 6]}.
	 */
	public byte getRoll() {
		return roll;
	}

	@Override
	public int hashCode() {
		return 129 * roll;
	}

	@Override
	public String toString() {
		return Byte.toString(roll);
	}
}
